Tenemos una aplicación C# .NET desarrollada internamente que estamos tratando de colocar en contenedores de Windows. La aplicación se diseñó originalmente para ejecutarse como un servicio, pero parece ser que los contenedores se ejecutan mejor como un proceso. Así que los desarrolladores han realizado algunos pequeños cambios y ahora podemos ejecutar la aplicación desde la línea de comandos. Se ejecuta correctamente en Win 10, 2012 R2, 2016 y 2019.
Sin embargo, cuando intentamos ejecutar exactamente la misma aplicación en un contenedor de 2016 o 2019, recibimos el mensaje de error:
No se puede iniciar el servicio desde la línea de comandos o un depurador. Primero se debe instalar un servicio de Windows (usando installutil.exe) y luego comenzar con ServerExplorer, la herramienta administrativa de servicios de Windows o el comando NET START.
¿Por qué la ejecución en un contenedor cambiaría la forma en que se ejecuta la aplicación? No hay dependencias (aparte de .NET) para la aplicación que no estén incluidas con la aplicación.
Puedo instalar correctamente la aplicación como servicio en el contenedor e iniciar el servicio sin errores. Sin embargo, intentar curvar http://localhost en el contenedor o fuera del contenedor falla incluso si el puerto está expuesto a través de la opción -p 80:80 de docker run.
He visto versiones anteriores de esta aplicación ejecutarse con éxito en un contenedor docker como un proceso, así que creo que tiene que ser una advertencia de C#, pero no soy un desarrollador y obtengo un estándar "se ejecuta en el host, debe ser una cosa de Docker" respuesta de nuestros desarrolladores.
Resulta que el código tenía una instrucción if en Environment.UserInteractive que le indicaba si debía comportarse como consola o como servicio. En los contenedores de Windows Docker, Environment.UserInteractive siempre se activa como falso por alguna razón que obliga a la aplicación a funcionar incluso cuando se ejecuta como una consola. Usamos una variable de entorno para anular el if.
Vale la pena señalar que aparentemente en .NET Core, la variable siempre se activa como verdadera, lo que puede ser útil dada la forma en que generalmente se activan las aplicaciones de Linux.